import os, sys, time
import threading, traceback

parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 5)))
sys.path.insert(0, parent_path)

from core.task.modules.task_lines.base_task import BaseTask
from core.utils.logger import logging
from core.task.modules.processors.steam_reader import *

from core.utils.trigger_exceptions import *

class LineLoopTask(BaseTask):
    """线性循环任务流程
    将线性与循环结合的任务流
    当任务启动后, 会开始循环执行, 并通过特殊的自定义Exception跳出循环后继续执行后处理的先行任务

    sample:
    比如我需要读取视频文件, 逐帧进行算法分析后将结果保存为视频, 保存完成后调用FFMPEG转码或者FTP上传
    """
    def __init__(self,
                 predictor, 
                 process,
                 preprocess, 
                 postprocess, 
                 line_postprocess,
                 trigger_exception, # 用于中断循环的Excetion类名, 详见 core.task.modules.processors.steam_reader
                 detector_tags = [],
                 keep_keys=[],
                 ) -> None:
        super().__init__(predictor,process,preprocess,postprocess,detector_tags)
        self.line_postprocess = line_postprocess
        self.trigger_exception = eval(trigger_exception)
        self.run_loop_thread = None
        self.keeps = {}
        self.kepp_keys = keep_keys

    def set(self,data):
        assert self.status == 0
        if not self.preprocessor is None:
            self.preprocessor.set(data)
        if not self.postprocessor is None:
            self.postprocessor.set(data)
        for key in self.kepp_keys:
            if data.get(key,False):
                self.keeps[key] = data[key]
     
    def run_loop(self):
        try:
            data = {}
            while True:
                data.clear()
                data["detector_tags"] = self.detector_tags
                data.update(self.keeps)
                for processor in self.exe_seq:
                    data = processor(data)
        except Exception as e:
            if isinstance(e, self.trigger_exception):
                self.line_postprocess(data)
                self.close()
            else:
                self.close()
                raise e
        finally:
            logging.info("|task run_loop done.|")

    def __call__(self, data):
        self.standby()
        return data

    def standby(self):
        try:
            super().standby()
            self.run_loop_thread = threading.Thread(target=self.run_loop)
            self.run_loop_thread.start()
        except Exception as e:
            raise e
